/**
 * 单仓位交易策略模拟器
 *
 * 功能说明：
 * 1. 监控多个交易对的价格变化
 * 2. 当某个交易对的前一根K线涨幅超过触发阈值时，在下一根K线开盘时建仓
 * 3. 同时只能持有一个仓位，建仓后等待止盈或止损
 * 4. 支持优先交易对筛选
 * 5. 相同币种2次持仓之间时间不能低于10分钟
 * 6. 建仓条件：前一根K线涨幅 > gainTriggerPct 且收盘价与最高价差距跟开盘价不超过10%
 *
 * 策略逻辑：
 * - 建仓条件：前一根K线涨幅 > gainTriggerPct 且收盘价与最高价差距跟开盘价不超过10
 * - 止盈条件：价格 >= 建仓价 * (1 + takeProfitPct/100)
 * - 止损条件：价格 <= 建仓价 * (1 - stopLossPct/100)
 * - 冷却期：同一币种两次建仓间隔必须 >= 10分钟
 */

/**
 * 计算涨幅百分比
 * @param {number} prevOpen - 前一根K线开盘价
 * @param {number} prevClose - 前一根K线收盘价
 * @returns {number} 涨幅百分比
 */
function calculateGainPct(prevOpen, prevClose) {
  return ((prevClose - prevOpen) / prevOpen) * 100;
}

/**
 * 计算收盘价与最高价的差距百分比
 * @param {number} prevClose - 前一根K线收盘价
 * @param {number} prevHigh - 前一根K线最高价
 * @returns {number} 差距百分比
 */
function calculateCloseToHighPct(prevClose, prevHigh, prevOpen) {
  return ((prevHigh - prevClose) / prevOpen) * 100;
}

/**
 * 模拟单仓位交易策略
 * @param {Array} klineData - 全部K线数据，包含多个交易对
 * @param {Object} config - 配置参数
 * @param {number} config.takeProfitPct - 止盈百分比
 * @param {number} config.stopLossPct - 止损百分比
 * @param {number} config.gainTriggerPct - 建仓触发涨幅百分比
 * @param {Array} config.prioritySymbols - 优先交易对列表，为空时交易所有对
 * @param {number} config.closeToHighPctTriggerPct - 收盘价与最高价差距触发百分比
 * @returns {Array} trades - 交易明细数组
 */
function simulateSinglePositionStrategy(klineData, config) {
  const { takeProfitPct, stopLossPct, gainTriggerPct, prioritySymbols,  closeToHighPctTriggerPct} = config;

  // 按时间分组，将同一时间点的多个交易对数据归类
  const timeMap = new Map();
  for (const item of klineData) {
    if (!timeMap.has(item.open_time)) {
      timeMap.set(item.open_time, []);
    }
    timeMap.get(item.open_time).push(item);
  }

  // 按时间顺序排序
  const sortedTimes = Array.from(timeMap.keys()).sort((a, b) => a - b);
  // 记录每个交易对的最新K线数据
  const lastCandles = new Map();
  // 存储所有交易记录
  const trades = [];
  // 当前持仓状态，null表示无持仓
  let currentPosition = null;
  // 记录每个交易对的最后建仓时间（毫秒）
  const lastEntryTimes = new Map();
  // 冷却期时间：10分钟 = 10 * 60 * 1000 毫秒
  const cooldownPeriod = 10 * 60 * 1000;

  // 遍历每个时间点
  for (const time of sortedTimes) {
    const candles = timeMap.get(time);

    // 持仓处理：检查止盈止损条件
    if (currentPosition) {
      // 找到当前持仓交易对的数据
      const candle = candles.find(c => c.symbol === currentPosition.symbol);
      if (!candle) continue;

      const high = parseFloat(candle.high);
      const low = parseFloat(candle.low);
    // 检查止盈条件：最高价达到止盈价
    if (high >= currentPosition.takeProfit) {
        trades.push({
          ...currentPosition,
          exit_price: currentPosition.takeProfit,
          exit_time: time,
          result: "TP", // Take Profit
          profit: takeProfitPct
        });
        currentPosition = null;
      } else // 检查止损条件：最低价达到止损价
      if (low <= currentPosition.stopLoss) {
        trades.push({
          ...currentPosition,
          exit_price: currentPosition.stopLoss,
          exit_time: time,
          result: "SL", // Stop Loss
          profit: -stopLossPct
        });
        currentPosition = null;
      }
    }

    // 建仓处理：只在无持仓时寻找建仓机会
    if (!currentPosition) {
      for (const candle of candles) {
        // 如果设置了优先交易对，则只交易指定的交易对
        if (prioritySymbols.length && !prioritySymbols.includes(candle.symbol)) continue;

        // 检查冷却期：同一币种两次建仓间隔必须 >= 10分钟
        const lastEntryTime = lastEntryTimes.get(candle.symbol);
        if (lastEntryTime && (time - lastEntryTime) < cooldownPeriod) {
          continue; // 跳过仍在冷却期的交易对
        }

        // 获取该交易对的前一根K线数据
        const prev = lastCandles.get(candle.symbol);
        if (prev) {
          // 计算前一根K线的涨幅
          const gainPct = calculateGainPct(parseFloat(prev.open), parseFloat(prev.close));
          // 计算前一根K线收盘价与最高价的差距
          const closeToHighPct = calculateCloseToHighPct(parseFloat(prev.close), parseFloat(prev.high), parseFloat(prev.open));

          // 如果涨幅超过触发阈值且收盘价与最高价差距不超过1%，则建仓
          if (gainPct > gainTriggerPct && closeToHighPct <= closeToHighPctTriggerPct) {
            const entry = parseFloat(candle.open);
            currentPosition = {
              symbol: candle.symbol,
              entry_time: time,
              entry: entry,
              closeToHighPct,
              takeProfit: entry * (1 + takeProfitPct / 100), // 计算止盈价
              stopLoss: entry * (1 - stopLossPct / 100)      // 计算止损价
            };
            // 记录该交易对的建仓时间
            lastEntryTimes.set(candle.symbol, time);
            break; // 建仓后退出循环，避免同时建多个仓位
          }
        }
      }
    }

    // 更新每个交易对的最新K线数据
    for (const candle of candles) {
      lastCandles.set(candle.symbol, candle);
    }
  }

  return trades;
}

export { simulateSinglePositionStrategy }
